package com.yilin.tms.data.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yilin.commons.exception.BusinessException;
import com.yilin.commons.factory.XSSFExcelFactory;
import com.yilin.commons.factory.XSSFRichString;
import com.yilin.commons.util.*;
import com.yilin.tms.core.application.PageData;
import com.yilin.tms.core.application.PlatRequest;

import com.yilin.tms.core.commons.utils.ParamUtil;
import com.yilin.tms.core.commons.utils.QueryUtil;
import com.yilin.tms.core.entity.data.bill.BillOption;
import com.yilin.tms.core.entity.data.bill.TruckerBill;
import com.yilin.tms.core.entity.order.payment.OrderSettlementCost;
import com.yilin.tms.core.entity.order.transit.TransitOrder;
import com.yilin.tms.core.entity.order.transit.TransitOrderNote;
import com.yilin.tms.core.entity.order.transit.TransitOrderNoteDetail;
import com.yilin.tms.core.entity.user.account.Account;
import com.yilin.tms.core.entity.user.auth.IdCard;
import com.yilin.tms.core.remote.IOrderRemote;
import com.yilin.tms.core.remote.IUserRemote;
import com.yilin.tms.data.components.PdfTool;
import com.yilin.tms.data.mapper.TruckerBillMapper;
import com.yilin.tms.data.service.IBillService;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.io.File;
import java.util.*;


@Service
@Transactional
public class BillService implements IBillService {

    @Resource
    TruckerBillMapper truckerBillMapper;
    @Resource
    IOrderRemote orderRemote;
    @Resource
    IUserRemote userRemote;
    @Resource
    PdfTool pdfTool;

    @Override
    public PageData<TruckerBill> getTruckerBillPage(TruckerBill query, Integer page, Integer limit) {
        QueryWrapper<TruckerBill> queryWrapper = QueryUtil.andQueryWrapper(new QueryWrapper<>(),query);
        return truckerBillMapper.selectPage(new PageData<>(page,limit),queryWrapper);
    }

    @Override
    public void addTruckerBill(Account loginUser, TruckerBill truckerBill, List<TransitOrder> transitOrderList, List<OrderSettlementCost> settlementList) {
        //車輛信息
        List<String> truckIds = ArrayUtil.fieldNoRepeatAdd(transitOrderList, TransitOrder::getTransitTruckId);
        truckerBill.setInvolvedVehicleIds(String.join(",", truckIds));
        List<String> truckInfos = ArrayUtil.fieldNoRepeatAdd(transitOrderList, order -> order.getTransitTruckNo() + "(" + order.getTransitTruckTypeName() + ")|" + order.getTransitTruckUserName());
        truckerBill.setInvolvedVehicleInfos(String.join(",", truckInfos));
        //駕駛員
        List<String> driverIds = ArrayUtil.fieldNoRepeatAdd(transitOrderList, TransitOrder::getTransitTruckUserId);
        truckerBill.setInvolvedDriverIds(String.join(",", driverIds));
        //运单号组
        List<String> noList = ArrayUtil.fieldAdd(transitOrderList, TransitOrder::getTransportNo);
        truckerBill.setInvolvedTransportNos(String.join(",", noList));
        //结算单组
        List<String> idList = ArrayUtil.fieldAdd(settlementList, OrderSettlementCost::getId);
        truckerBill.setInvolvedSettlementIds(String.join(",", idList));
        //节点组
        List<TransitOrderNote> transitOrderNoteList = ParamUtil.isSuccess(orderRemote.getTransitOrderNoteListByTransitOrderIds(truckerBill.getInvolvedOrderIds()));
        List<String> noteIdList = ArrayUtil.fieldAdd(transitOrderNoteList, TransitOrderNote::getId);
        truckerBill.setInvolvedNoteIds(String.join(",", noteIdList));
        //涉及區域
        ArrayList<String> orAreaList = new ArrayList<>(), eeAreaList = new ArrayList<>();
        for (TransitOrderNote transitOrderNote : transitOrderNoteList) {
            ArrayUtil.notRepeatAdd(orAreaList,transitOrderNote.getConsignorArea());
            ArrayUtil.notRepeatAdd(eeAreaList,transitOrderNote.getConsigneeArea());
        }
        String orLongAddress = ArrayUtil.toLongAddress(orAreaList);
        String eeLongAddress = ArrayUtil.toLongAddress(eeAreaList);
        truckerBill.setInvolvedAreas(orLongAddress+"→"+eeLongAddress);
        //涉及货物
        List<TransitOrderNoteDetail> noteDetailList = ParamUtil.isSuccess(orderRemote.getAllTransitDetailListByTransitOrderIds(truckerBill.getInvolvedOrderIds()));
        List<String> goodsNameList = ArrayUtil.fieldNoRepeatAdd(noteDetailList, obj -> {
            if (obj.getGoodsTypeName()==null) obj.setGoodsTypeName("普货");
            if (obj.getGoodsName()==null) obj.setGoodsName("其他");
            return obj.getGoodsTypeName() + "/" + obj.getGoodsName();
        });
        truckerBill.setInvolvedGoodsNames(String.join(",",goodsNameList));
        //开票金额
        double invoicedAmount = ArrayUtil.numListAdd(settlementList, OrderSettlementCost::getSettlementCost);
        truckerBill.setTotalInvoicedAmount(invoicedAmount);
        //车主身份证
        IdCard idCard = ParamUtil.isSuccess(userRemote.getIdCardByUserId(truckerBill.getOrganizeAdminId()));
        truckerBill.setIdCardNo(idCard.getIdCardNo());
        truckerBill.setWaybillCount(transitOrderList.size());
        truckerBill.setBillDownloadCount(0);
        truckerBill.setBillStatus(TruckerBill.BillStatus.create);
        truckerBill.setInitiateUserId(loginUser.getId());
        truckerBill.setInitiateUserName(loginUser.getName());
        truckerBillMapper.insert(truckerBill);
        //批量更新运单开票状态
        orderRemote.updateTransitOrdersBillStatus(truckerBill.getInvolvedOrderIds(),true);
    }

    @Override
    public String generatePdf(Account loginUser, String filePath, TruckerBill truckerBill, BillOption billOption) {
        List<String> htmlList = new ArrayList<>();
        //车主证件
        if (billOption.isTruckerBill()){
            htmlList.add(PlatRequest.selfGet(loginUser.getToken(), "/data/views/userMaterial", MapUtil.generate(map -> {
                map.put("accountId",truckerBill.getOrganizeAdminId());
                map.put("pdfPrint", true);
            })));
        }
        //代开协议
        if (billOption.isAgencyBill()){
            htmlList.add(PlatRequest.selfGet(loginUser.getToken(), "/data/views/invoiceAgreement", MapUtil.generate(map -> {
                map.put("organizeId", truckerBill.getOrganizeId());
                map.put("pdfPrint", true);
            })));
        }
        //司机证件
        if (billOption.isDriverBill()){
            String[] driverIds = truckerBill.getInvolvedDriverIds().split(",");
            for (String driverAccountId : driverIds) {
                htmlList.add(PlatRequest.selfGet(loginUser.getToken(), "/data/views/driverMaterial", MapUtil.generate(map -> {
                    map.put("accountId", driverAccountId);
                    map.put("pdfPrint", true);
                })));
            }
        }
        //车辆证件
        if (billOption.isVehicleBill()){
            String[] vehicleIds = truckerBill.getInvolvedVehicleIds().split(",");
            for (String  vehicleId : vehicleIds) {
                htmlList.add(PlatRequest.selfGet(loginUser.getToken(), "/data/views/vehicleMaterial", MapUtil.generate(map -> {
                    map.put("vehicleId", vehicleId);
                    map.put("pdfPrint", true);
                })));
            }
        }
        //运单列表
        if (billOption.isTransitBill()){
            htmlList.add(PlatRequest.selfGet(loginUser.getToken(), "/data/views/elcTransitOrderList", MapUtil.generate(map -> {
                map.put("transitOrderIds", truckerBill.getInvolvedOrderIds());
                map.put("pdfPrint", true);
            })));
        }
        //结款单列表
        if (billOption.isSettlementBill()){
            htmlList.add(PlatRequest.selfGet(loginUser.getToken(), "/data/views/elcSettlementOrderList", MapUtil.generate(map -> {
                map.put("orderSettlementCostIds",  truckerBill.getInvolvedSettlementIds());
                map.put("pdfPrint", true);
            })));
        }
        //合同（三方）
        if (billOption.isContractBill()){
            String[] transitOrderIds = truckerBill.getInvolvedOrderIds().split(",");
            for (String transitOrderId : transitOrderIds) {
                htmlList.add(PlatRequest.selfGet(loginUser.getToken(), "/data/views/contractHtml", MapUtil.generate(map -> {
                    map.put("transitOrderId", transitOrderId);
                    map.put("pdfPrint", true);
                })));
            }
        }
        //回执单
        if (billOption.isReceiptBill()){
            String[] involvedNoteIds = truckerBill.getInvolvedNoteIds().split(",");
            for (String involvedNoteId : involvedNoteIds) {
                htmlList.add(PlatRequest.selfGet(loginUser.getToken(), "/data/views/elcReceiptOrder", MapUtil.generate(map -> {
                    map.put("transitOrderNoteId", involvedNoteId);
                    map.put("pdfPrint", true);
                })));
            }
        }
        for (String s : htmlList) {
            if (StringUtil.isEmpty(s)) throw new BusinessException("部分数据生成HTML缺失，为保证数据完成性，本次生产作废！");
        }
        String fileName = String.format("%s[%s条运单]%s",truckerBill.getOrganizeAdminName(),truckerBill.getWaybillCount(), DateTimeUtil.dateToString(new Date(),"yyyy-MM-dd"));
        boolean success = pdfTool.htmlToPdf(htmlList, String.format("%s%s.pdf",filePath,fileName));
        if (!success) return String.format("%s%s.pdf",filePath,fileName);
        return pdfTool.addWaterMarkRep(filePath, fileName,loginUser.getOrganizeName());
    }

    /**
     * 车主/司机 证件 + 代开协议
     * */
    @Override
    public String generateTruckerPdf(Account loginUser, String filePath, String[] accountIds) {
        List<String> htmlList = new ArrayList<>();
        Map<String,List<String>> organizeIdMap = new HashMap<>();
        List<Account> accountList = ParamUtil.isSuccess(userRemote.getAccountListByIds(String.join(",", accountIds)));
        for (Account account : accountList){
            organizeIdMap.computeIfAbsent(account.getOrganizeId(), s -> new ArrayList<>());
            organizeIdMap.get(account.getOrganizeId()).add(account.getId());
        }
        organizeIdMap.forEach((organizeId, accountIdList) -> {
            //代开协议
            htmlList.add(PlatRequest.selfGet(loginUser.getToken(), "/data/views/invoiceAgreement", MapUtil.generate(map -> {
                map.put("organizeId",organizeId);
                map.put("pdfPrint", true);
            })));
            //车主/司机证件
            for (String accountId : accountIdList) {
                htmlList.add(PlatRequest.selfGet(loginUser.getToken(), "/data/views/driverMaterial", MapUtil.generate(map -> {
                    map.put("accountId",accountId);
                    map.put("pdfPrint", true);
                })));
            }
        });
        String fileName = String.format("司机信息单[%s条记录]%s",accountIds.length,DateTimeUtil.dateToString(new Date(),"yyyy-MM-dd"));
        boolean success = PdfUtil.html2Pdf(htmlList, String.format("%s%s.pdf",filePath,fileName));
        if (!success) return null;
        return PdfUtil.addWaterMarkRep(filePath, fileName, loginUser.getOrganizeName());
    }

    /**
     * 车辆信息单
     * */
    @Override
    public String generateVehiclePdf(Account loginUser, String filePath, String[] vehicleIds) {
        List<String> htmlList = new ArrayList<>();
        //车辆证件
        for (String vehicleId : vehicleIds) {
            htmlList.add(PlatRequest.selfGet(loginUser.getToken(), "/data/views/vehicleMaterial", MapUtil.generate(map -> {
                map.put("vehicleId",vehicleId);
                map.put("pdfPrint", true);
            })));
        }
        String fileName = String.format("车辆信息单[%s条记录]%s",vehicleIds.length,DateTimeUtil.dateToString(new Date(),"yyyy-MM-dd"));
        boolean success = PdfUtil.html2Pdf(htmlList, String.format("%s%s.pdf",filePath,fileName));
        if (!success) return null;
        return PdfUtil.addWaterMarkRep(filePath, fileName, loginUser.getOrganizeName());
    }

    /**
     * 运单信息列表 + 合同
     * */
    @Override
    public String generateTransitOrderPdf(Account loginUser, String filePath, String[] transitOrderIds) {
        List<String> htmlList = new ArrayList<>();
        //运单信息列表
        htmlList.add(PlatRequest.selfGet(loginUser.getToken(), "/data/views/elcTransitOrderList", MapUtil.generate(map -> {
            map.put("transitOrderIds", String.join(",",transitOrderIds));
            map.put("pdfPrint", true);
        })));
        //合同（三方）
        for (String transitOrderId : transitOrderIds) {
            htmlList.add(PlatRequest.selfGet(loginUser.getToken(), "/data/views/contractHtml", MapUtil.generate(map -> {
                map.put("transitOrderId", transitOrderId);
                map.put("pdfPrint", true);
            })));
        }
        String fileName = String.format("运单信息单[%s条记录]%s",transitOrderIds.length,DateTimeUtil.dateToString(new Date(),"yyyy-MM-dd"));
        boolean success = PdfUtil.html2Pdf(htmlList, String.format("%s%s.pdf",filePath,fileName));
        if (!success) return null;
        return PdfUtil.addWaterMarkRep(filePath, fileName, loginUser.getOrganizeName());
    }

    /**
     * 结算信息单列表
     * */
    @Override
    public String generateSettlementOrderPdf(Account loginUser, String filePath, String[] settlementCostIds) {
        List<String> htmlList = new ArrayList<>();
        //结算信息列表
        htmlList.add(PlatRequest.selfGet(loginUser.getToken(), "/data/views/elcSettlementOrderList", MapUtil.generate(map -> {
            map.put("orderSettlementCostIds", String.join(",",settlementCostIds));
            map.put("pdfPrint", true);
        })));
        String fileName = String.format("结算信息单[%s条记录]%s",settlementCostIds.length,DateTimeUtil.dateToString(new Date(),"yyyy-MM-dd"));
        boolean success = PdfUtil.html2Pdf(htmlList, String.format("%s%s.pdf",filePath,fileName));
        if (!success) return null;
        return PdfUtil.addWaterMarkRep(filePath, fileName, loginUser.getOrganizeName());
    }

    /**
     * 回单信息单
     * */
    @Override
    public String generateReceiptOrderPdf(Account loginUser, String filePath, String[] transitOrderNoteIds) {
        List<String> htmlList = new ArrayList<>();
        //回单信息单
        for (String involvedNoteId : transitOrderNoteIds) {
            htmlList.add(PlatRequest.selfGet(loginUser.getToken(), "/data/views/elcReceiptOrder", MapUtil.generate(map -> {
                map.put("transitOrderNoteId", involvedNoteId);
                map.put("pdfPrint", true);
            })));
        }
        String fileName = String.format("回单信息单[%s条记录]%s",transitOrderNoteIds.length,DateTimeUtil.dateToString(new Date(),"yyyy-MM-dd"));
        boolean success = PdfUtil.html2Pdf(htmlList, String.format("%s%s.pdf",filePath,fileName));
        if (!success) return null;
        return PdfUtil.addWaterMarkRep(filePath, fileName, loginUser.getOrganizeName());
    }

    @Override
    public String generateExcel(Account loginUser,String filePath, List<TruckerBill> billList) {
        String date = DateTimeUtil.dateToString(new Date(), "yyyy-MM-dd");
        double amt = ArrayUtil.numListAdd(billList, TruckerBill::getTotalInvoicedAmount);
        //创建工作表
        XSSFExcelFactory instance = XSSFExcelFactory.newInstance("开票明细清单");
        instance.setColumnWidth(ArrayUtil.initArr(6,10,20,10,12,80));
        //创建标题【首行,合并单元格数量：6】
        instance.createBillTitle(loginUser.getOrganizeName()+"代司机开票明细清单",6);
        //创建统计行【次行,合并单元格数量：6】
        XSSFRichString statistics = new XSSFRichString();
        XSSFFont valueFont = instance.createFont(true,11f);
        statistics.connect("列表创建日期：").connect(date,valueFont).append("，");
        statistics.connect("开票数量：").connect(String.valueOf(billList.size()),valueFont).append("个，");
        statistics.connect("开票总金额合计：￥").connect(CommonUtil.formatDoubleTwo(amt),valueFont).append("元");
        instance.createBillStatistics(statistics,6);
        //创建标题栏【行统一数量 6】
        instance.createBillTableHead(ArrayUtil.initArr("序号","车主名称","身份证号","运单数量","开票金额","发票备注栏"));
        //开始创建数据
        List<XSSFExcelFactory.ContentCell[]> contentList = new ArrayList<>();
        for (int i = 0; i < billList.size(); i++) {
            TruckerBill bill = billList.get(i);
            XSSFExcelFactory.ContentCell[] contentCells = ArrayUtil.initArr(XSSFExcelFactory.ContentCell.class, 6);
            contentCells[0].setIntCellValue(i+1);
            contentCells[1].setTextCellValue(bill.getOrganizeAdminName());
            contentCells[2].setTextCellValue(bill.getIdCardNo());
            contentCells[3].setIntCellValue(bill.getWaybillCount());
            contentCells[4].setDoubleCellValue(CommonUtil.doubleTwo(bill.getTotalInvoicedAmount()),"¥##0.00;¥-##0.00");
            XSSFRichString xssRichRemark = new XSSFRichString();
            XSSFColor textGayColor = new XSSFColor(new java.awt.Color(128, 132, 143)); //accepts a short value
            ///缩短车辆信息，车辆大于3时，用等代替
            String[] split1 = bill.getInvolvedVehicleInfos().split(",");
            for (int i1 = 0; i1 < split1.length; i1++) split1[i1] = split1[i1].split("\\|")[0];
            String vehicleInfos = String.join("、",split1);
            if (split1.length > 3) vehicleInfos = String.join("、",ArrayUtil.splitArr(split1,0,3))+" 等";
            xssRichRemark.connect("车辆信息: ",instance.createFont(textGayColor,10f)).connect(vehicleInfos);
            //缩短地区信息，起/终地区省大于1，市缩短显示为省内，市大于1，区缩短显示为市内，区大于2,用等代替
            String[] startAndEnd = bill.getInvolvedAreas().split("→");
            for (int n = 0; n < startAndEnd.length; n++) startAndEnd[n] = ArrayUtil.longAddressShort(startAndEnd[n]);
            xssRichRemark.connect("\n地点信息: ",instance.createFont(textGayColor,10f)).connect(String.join("->",startAndEnd));
            //缩短货物信息，货物信息大于3时，用等代替
            String involvedGoodsNames = bill.getInvolvedGoodsNames();
            if (split1.length > 4) involvedGoodsNames = String.join("、",ArrayUtil.splitArr(split1,0,4))+" 等";
            xssRichRemark.connect("\n货物信息: ",instance.createFont(textGayColor,10f)).connect(involvedGoodsNames);
            xssRichRemark.connect("\n请依法自行申报缴纳个人所得税",instance.createFont(textGayColor,10f));
            contentCells[5].setCellValue(xssRichRemark);
            contentCells[5].setAlignment(HorizontalAlignment.LEFT);
            contentCells[5].setWrapText(true);
            contentList.add(contentCells);
        }
        //创建数据 完成列表数据写入
        instance.createBillContent(contentList);
        String fileName = String.format("开票明细清单 %s",date);
        File file = new File(filePath, String.format("%s.xls", fileName));
        instance.writeToFile(file);
        return file.getPath();
    }

    @Override
    public List<TruckerBill> getTruckerBillsByIds(String[] truckerBillIds) {
        return truckerBillMapper.selectBatchIds(ArrayUtil.initList(truckerBillIds));
    }

    @Override
    public void scrapTruckerBill(Account loginUser, List<TruckerBill> truckerBillList) {
        List<String> tInvolvedOrderIds = new ArrayList<>();
        for (TruckerBill truckerBill : truckerBillList) {
            truckerBill.setBillStatus(TruckerBill.BillStatus.scrap);
            truckerBill.setDealUserId(loginUser.getId());
            truckerBill.setDealUserName(loginUser.getName());
            truckerBill.setDealTime(new Date());
            truckerBillMapper.updateById(truckerBill);
            tInvolvedOrderIds.add(truckerBill.getInvolvedOrderIds());//“xxxx,xxxx”,“xxxx,xxxx”
        }
        //批量更新运单开票状态
        String tInvolvedOrderIdStr = String.join(",",tInvolvedOrderIds);
        orderRemote.updateTransitOrdersBillStatus(tInvolvedOrderIdStr,false);
    }


}
